#ifndef PARSER_H
#define PARSER_H
#include "global.h"
#include "as-node.h"
#include <vector>
#include <list>
#include <set>

namespace tinyscript{
namespace internal{
class Scanner;

// A parse scope is the scope that handles the name space of all the declared
// variable. It is used to detect errors like reference undeclared variable 
// or redefinition of certain variable. A ParseScope will be exit and deleting
// all the related resource automatically once the parser exists such scope.
// It is a context like information. For those sentence who a required a specific
// scope, this is typically useful. And these parser routine should take responsibility
// for managing the parser scope API.
class ParserScope {
public:
	class ParserScopeAuto{
	public:
		inline ParserScopeAuto( ParserScope& ps );
		inline ~ParserScopeAuto();
	private:
		ParserScope& scope_;
	};
public:
	class Scope {
		typedef std::set<std::string> ScopeVariableList;
	public:
		bool QuerySymbol( const std::string& name );
		bool DecSymbol( const std::string& name );
	private:
		Scope( ParserScope* scope ):
		   scope_(scope){}
		~Scope() {}
	private:
		ScopeVariableList scope_variable_;
		friend class ParserScope;
		ParserScope* scope_;
	};
	Scope* CurrentScope() const {
		return scope_stack_.back();
	}
	void EnterScope() {
		scope_stack_.push_back( new Scope(this) );
	}
	void ExitScope() {
		delete scope_stack_.back();
		scope_stack_.pop_back();
	}
private:
	typedef std::list<Scope*> ScopeChain;
	ScopeChain scope_stack_;
	friend class Scope;
};
// This parser will parse the whole script and generates a lightweight syntax tree.
// However, to avoid large memory footprint, the parser can be used to stop a certain
// point and emit all the machine code ,then free the syntax tree and continue parsing
class Parser {
public:

    class ParsingTerminator {
    public:
        void Clear() {
			token_list_.clear();
			last_terminator_.set_token( Token::TT_ERROR );
		}
        void AddTerminator( int i ) {
            token_list_.push_back(i);
        }
        bool Decide( const Token& tk) const {
            for( size_t i = 0 ; i < token_list_.size() ; ++i ) {
                if( token_list_[i] == tk.token() ) {
					last_terminator_ = tk;
                    return true;
				}
            }
            return false;
        }
		const Token& last_terminator() const {
			return last_terminator_;
		}
		static ParsingTerminator kNullTerminator;
	private:
        std::vector<int> token_list_;
		mutable Token last_terminator_;
    };

    Parser( Scanner& scanner );
	~Parser();

	const std::string& error_description() const {
		return error_description_;
	}

	ASNode* ParseChunk( bool* status );
	ASNode* ParseModule( bool* status );
	ASNode* ParseCodeBlock( bool* status );

private:

	void ReportError( const std::string& );
	ASNode* ParseExpression(  const ParsingTerminator& term, bool* status );
	ASNode* ParseListAccessor( const Token& tk , bool* status );
	ASNode* ParseAtomicValue( const Token& tk , bool* status );
	ASNode* ParseOperand( const Token& tk ,bool* status );
    ASNode* ParseUnary( const Token& tk , bool* status );
	ASNode* ParseSymbol( const Token& tk , bool* status );
	ASNode* ParseFunctionInvoke( const Token& tk , bool* status );

	ASNode* ParseControlKeyword( bool* status );
	ASNode* ParseVarDeclarationOrLeftHandSideValue( bool* status );
	ASNode* ParseVarDeclarationOrWithAssignment( const ParsingTerminator& term , bool* status , bool ensure_assignment = true );

	ASNode* ParseRightHandSideValue( const ParsingTerminator& term , bool* status );
    ASNode* ParseFunctionDefine( const Token& tk , bool* status );
	ASNode* ParseReturn( const Token& tk , bool* status );

    ASNode* ParseIf(  const Token& , bool* status );
    ASNode* ParseElseIf( bool* status );
    ASNode* ParseElse( bool* status );
    ASNode* ParseFor(  const Token& , bool* status );
	ASNode* ParseFor_Init( bool* status );
	ASNode* ParseFor_Condition( bool* status );
	ASNode* ParseFor_Step( bool* status );


    ASNode* ParseWhile(  const Token& , bool* status );
    ASNode* ParseForeach( const Token& , bool* status );
	ASNode* ParseConditionAndBody( ASNode** condition , ASNode** body , bool* status );

	ASNode* ParseStatement( bool* status );

    ASNode* ParseListDefine(  const Token& tk, bool* status );
	ASNode* ParseListAssignment( bool* status );

private:
    Scanner& scanner_;
	ASNodePage node_page_;
	std::string error_description_;
	ParserScope scope_;
	DISALLOW_COPY_AND_ASSIGN(Parser);
};

ParserScope::ParserScopeAuto::ParserScopeAuto( ParserScope& ps ) :
scope_(ps){
	ps.EnterScope();
}

ParserScope::ParserScopeAuto::~ParserScopeAuto(){
	scope_.ExitScope();
}

}// namespace internal
}// namespace sscript

#endif // PARSER_H
